package com.minimalist.common.config.bucket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.Duration;

/**
 * @author 11987
 */
@Component
public class DynamicRateLimitCalculator{
    private static final Logger log = LoggerFactory.getLogger(DynamicRateLimitCalculator.class);

    @Value("${dynamic-rate-limit.base-limit:100}")
    private int baseLimit;

    @Value("${dynamic-rate-limit.cpu-threshold-high:0.8}")
    private double cpuThresholdHigh;

    @Value("${dynamic-rate-limit.cpu-threshold-medium:0.6}")
    private double cpuThresholdMedium;

    @Value("${dynamic-rate-limit.memory-threshold-high:0.8}")
    private double memoryThresholdHigh;

    @Value("${dynamic-rate-limit.memory-threshold-medium:0.6}")
    private double memoryThresholdMedium;

    public RateLimitConfig calculateLimit(SystemMetrics metrics){
        int limit = baseLimit;
        limit = adjustLimitBasedOnCpu(limit, metrics.getCpuLoad());
        limit = adjustLimitBasedOnMemory(limit, metrics.getMemoryUsage());
        Duration refillDuration = calculateRefillDuration(metrics);
        return new RateLimitConfig(limit, refillDuration);
    }

    private int adjustLimitBasedOnCpu(int currentLimit, double cpuLoad){
        if (cpuLoad > cpuThresholdHigh){
            return (int) (currentLimit * 0.3);
        } else if (cpuLoad > cpuThresholdMedium){
            return (int) (currentLimit * 0.6);
        }
        return currentLimit;
    }

    private int adjustLimitBasedOnMemory(int currentLimit, double memoryUsage){
        if (memoryUsage > memoryThresholdHigh){
            return (int) (currentLimit * 0.4);
        } else if (memoryUsage > memoryThresholdMedium){
            return (int) (currentLimit * 0.7);
        }
        return currentLimit;
    }

    private Duration calculateRefillDuration(SystemMetrics metrics){
        double maxLoad = Math.max(metrics.getCpuLoad(),
                metrics.getMemoryUsage());
        if (maxLoad > 0.8){
            return Duration.ofMinutes(2);
        } else if (maxLoad > 0.5){
            return Duration.ofMinutes(1);
        }
        return Duration.ofSeconds(30);
    }
}

